package mymyoux.phidgets
{
	import com.phidgets.PhidgetSpatial;
	import com.phidgets.PhidgetSpatialEventData;
	import com.phidgets.events.PhidgetDataEvent;
	import com.phidgets.events.PhidgetErrorEvent;
	import com.phidgets.events.PhidgetEvent;
	
	import flash.events.ErrorEvent;
	
	import mymyoux.signals.Signal;

	/**
	 * Use Spatial Phidget Easily
	 */
	public class Spatial
	{
		/**
		 * Rate step
		 */
		public static const RATE_STEP:uint = 8;
		/**
		 * Minimum rate
		 */
		public static const MIN_RATE:uint = 8;
		/**
		 * Maximum rate
		 */
		public static const MAX_RATE:uint = 496;
		/**
		 * Spatial Phidget
		 */
		private var _spatial:PhidgetSpatial;
		/**
		 * @private
		 */
		private var _host:String;
		/**
		 * @private
		 */
		private var _port:uint;
		/**
		 * @private
		 */
		private var _password:String;
		/**
		 * @private
		 */
		private var _serialNumber:Number;
		/**
		 * @private
		 */
		private var _rate:uint;
		/**
		 * @private
		 */
		private var _signalError:Signal;
		/**
		 * @private
		 */
		private var _signalAcceleration:Signal;
		/**
		 * @private
		 */
		private var _signalAngular:Signal;
		/**
		 * @private
		 */
		private var _signalMagnetic:Signal;
		/**
		 * @private
		 */
		private var _signalAllData:Signal;
		/**
		 * @private
		 */
		private var _signalStatus:Signal;
		/**
		 * Create a spatial object
		 * @param host Host ip
		 * @param port Host port
		 * @param rate Default rate
		 */
		public function Spatial(host:String = "localhost", port:uint = 5001, password:String = null, serialNumber:Number = 0x7FFFFFFF, rate:uint = 32)
		{
			_spatial = new PhidgetSpatial();
			_spatial.addEventListener(PhidgetEvent.CONNECT,	onConnect);
			_spatial.addEventListener(PhidgetEvent.DISCONNECT, onDisconnect);
			_spatial.addEventListener(PhidgetEvent.DETACH,	onDetach);
			_spatial.addEventListener(PhidgetEvent.ATTACH,	onAttach);
			_spatial.addEventListener(PhidgetErrorEvent.ERROR, onError);
			_spatial.addEventListener(PhidgetDataEvent.SPATIAL_DATA, onSpatialData);
			_host = host;
			_port = port;
			_password = password;
			_serialNumber = serialNumber;
			this.rate = rate;
			
			_signalAcceleration = new Signal(Number, Number, Number, Number);
			_signalAngular = new Signal(Number, Number, Number, Number);
			_signalMagnetic = new Signal(Number, Number, Number, Number);
			_signalAllData = new Signal(Number, Number, Number, Number, Number, Number, Number, Number, Number, Number);
			_signalStatus = new Signal(Boolean);
			_signalError = new Signal(Error);
			
		}

		/**
		 * Host ip
		 */
		public function get host():String
		{
			return _host;
		}

		public function set host(value:String):void
		{
			_host = value;
		}

		/**
		 * Host port
		 */
		public function get port():uint
		{
			return _port;
		}

		public function set port(value:uint):void
		{
			_port = value;
		}

		/**
		 * Serial Number
		 */
		public function get serialNumber():Number
		{
			return _serialNumber;
		}

		public function set serialNumber(value:Number):void
		{
			_serialNumber = value;
		}

		/**
		 * Password
		 */
		public function get password():String
		{
			return _password;
		}


		public function set password(value:String):void
		{
			_password = value;
		}

		/**
		 * Dispatches a signal on acceleration data, angular rate data, magnetic data.
		 * dispatch(Time(<b>Number</b>), AccelerationX(<b>Number</b>),  AccelerationY(<b>Number</b>),  AccelerationZ(<b>Number</b>), AngularRateX(<b>Number</b>),  AngularRateY(<b>Number</b>),  AngularRateZ(<b>Number</b>), MagneticFieldX(<b>Number</b>),  MagneticFieldY(<b>Number</b>),  MagneticFieldZ(<b>Number</b>));
		 */
		public function get signalAllData():Signal
		{
			return _signalAllData;
		}

		/**
		 * Dispatches a signal on a status change. Connected or disconnected
		 * dispatch(connected(<b>Boolean</b>));
		 */
		public function get signalStatus():Signal
		{
			return _signalStatus;
		}
		/**
		 * Dispatches a signal on magnetic data.
		 * dispatch(Time(<b>Number</b>), MagneticFieldX(<b>Number</b>),  MagneticFieldY(<b>Number</b>),  MagneticFieldZ(<b>Number</b>));
		 */
		public function get signalMagnetic():Signal
		{
			return _signalMagnetic;
		}

		/**
		 * Dispatches a signal on angular rate data.
		 * dispatch(Time(<b>Number</b>), AngularRateX(<b>Number</b>),  AngularRateY(<b>Number</b>),  AngularRateZ(<b>Number</b>));
		 */
		public function get signalAngular():Signal
		{
			return _signalAngular;
		}
		/**
		 * Dispatches a signal on acceleration data
		 * dispatch(Time(<b>Number</b>), AccelerationX(<b>Number</b>),  AccelerationY(<b>Number</b>),  AccelerationZ(<b>Number</b>));
		 */
		public function get signalAcceleration():Signal
		{
			return _signalAcceleration;
		}
		/**
		 * Dispatches a signal on a error.
		 * dispatch(Error(<b>Error</b>));
		 */
		public function get signalError():Signal
		{
			return _signalError;
		}

		/**
		 * Data rate
		 */
		public function get rate():uint
		{
			return _rate;
		}

		public function set rate(value:uint):void
		{
			value = value - value % RATE_STEP;
			_rate = value;
			if(_rate < MIN_RATE)
			{
				_rate = MIN_RATE;
			}
			if(_rate > MAX_RATE)
			{
				_rate = MAX_RATE;
			}
			if(_spatial.isAttached)
			{
				_spatial.DataRate = _rate;	
			}
		}
		/**
		 * Start listening
		 */
		public function connect():void
		{
			_spatial.open(_host, _port, _password, _serialNumber);
		}
		/**
		 * Stop listening
		 */
		public function disconnect():void
		{
			_spatial.close();
		}
		/**
		 * @private
		 */
		private function onError(evt:PhidgetErrorEvent):void {

			_signalError.dispatch(evt.Error);
		}
		/**
		 * @private
		 */
		private function onAttach(evt:PhidgetEvent):void{
			_spatial.DataRate = _rate; //slow down the data rate
			_signalStatus.dispatch(true);
		}
		/**
		 * @private
		 */
		private function onDetach(evt:PhidgetEvent):void
		{
			_signalStatus.dispatch(false);
		}
		/**
		 * @private
		 */
		private function onConnect(evt:PhidgetEvent):void{
			
		}
		/**
		 * @private
		 */
		private function onDisconnect(evt:PhidgetEvent):void{
			
		}
		/**
		 * @private
		 */
		private function onSpatialData(evt:PhidgetDataEvent):void{
			var sData:PhidgetSpatialEventData = evt.Data as PhidgetSpatialEventData;
			
			_signalAcceleration.dispatch(sData.Time, Number(sData.Acceleration[0]), Number(sData.Acceleration[1]), Number(sData.Acceleration[2]));
			_signalAngular.dispatch(sData.Time, Number(sData.AngularRate[0]), Number(sData.AngularRate[1]), Number(sData.AngularRate[2]));
			_signalMagnetic.dispatch(sData.Time, Number(sData.MagneticField[0]), Number(sData.MagneticField[1]), Number(sData.MagneticField[2]));
			_signalAllData.dispatch(sData.Time,Number(sData.Acceleration[0]), Number(sData.Acceleration[1]), Number(sData.Acceleration[2]), Number(sData.AngularRate[0]), Number(sData.AngularRate[1]), Number(sData.AngularRate[2]), Number(sData.MagneticField[0]), Number(sData.MagneticField[1]), Number(sData.MagneticField[2]));
		}
	}
}

